Java アプリケーションのメモリリークを調査する強力なツールである Eclipse Memory Analyser Tool を使用して、XPages アプリケーションのメモリリークを調査する方法について紹介します。
Java ヒープダンプは、Java 仮想マシンのヒープメモリにある Java オブジェクトの現在の状態ダンプです。ヒープダンプはバイナリのデータで、それを読むためには Eclipse Memory Analyser Tool (www.eclipse.org/mat) が必要になります。
Domino で取得できるヒープダンプは IBM JVM のヒープダンプフォーマットで書かれているため、Eclipse Memory Analyser Tool に IBM の提供するプラグインである IBM Diagnostic Tool Framework for Java Version 1.10 (http://www.ibm.com/developerworks/java/jdk/tools/dtfj.html) を追加する必要があります。
Eclipse Memory Analyser Tool の準備
Eclipse Memory Analyzer Tool は Eclipse IDE のプラグインとしても、単体の RCP プログラムとしても公開されています。
ここでは Eclipse IDE のプラグインとして構成し、さらに IBM Diagnostic Tool Framework for Java を追加でインストールする方法を紹介します。
Eclipse Ganymede SR2 (3.4.2) のインストール
・・・記載予定・・・
Eclipse Memory Analyzer Tool のインストール
・・・記載予定・・・
IBM Diagnostic Tool Framework for Java のインストール
・・・記載予定・・・
この記事では実際に XPages アプリケーションでメモリリークを起こさせて、それが MAT でどのように発見できるかを見てみます。試した環境は以下になります。
Domino: IBM Domino 8.5.3 FP3
MAT 環境:
Eclipse Ganymede SR2 - Eclipse IDE for Java EE Developers
Eclipse Memory ANalyzer Tool 1.2.1
IBM Diagnostic Tool Framework for Java Version 1.10
この記事では実際に XPages アプリケーションでメモリリークを起こさせて、それが MAT でどのように発見できるかを見てみます。
サンプルとして使用するのは以下のような XPage アプリケーションです。このアプリションでは入力フィールドに設定されたサイズの配列のデータを作成しスコープ変数の applicationScope 変数に値を設定します。アプリケーションスコープの変数は、XPages アプリケーションとしてデータを保持するので、大きな値を設定することでメモリを圧迫させることができます。この記事での動作確認では入力フィールドに「500」を設定し、500MB のデータを生成しました。
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:label value="Leak data size: " id="label1"></xp:label>
<xp:inputText id="inputRepeatCount" required="true">
<xp:this.converter>
<xp:convertNumber type="number"></xp:convertNumber>
</xp:this.converter>
<xp:this.validators>
<xp:validateRequired message="Data size is mandatory,"></xp:validateRequired>
<xp:validateLongRange minimum="1" maximum="1000"></xp:validateLongRange>
</xp:this.validators>
</xp:inputText>
<xp:label value="MB" id="label2"></xp:label>
<xp:button value="Generate Memory Leak" id="buttonGenMemLeak">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="panelMessage">
<xp:this.action><![CDATA[#{javascript:
var repeat = getComponent("inputRepeatCount").getValue();
print ("Generating memory leak with " + repeat + " MB.");
var testdata_16 = "0123456789ABCDEF";
var testdata_1024 = "";
for (i=0; i<64; i++) {
testdata_1024 = testdata_1024 + testdata_16;
}
var listsize = 1024 * repeat;
var list = new Array(listsize);
for (j=0; j< listsize; j++) {
list[j] = testdata_1024;
}
applicationScope.testdatalist = list;
viewScope.message = list.length + "x1024 bytes data was stored in applicationScope.";
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
 
<xp:button value="Clear Memory Leak" id="buttonClearMemLeak">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" disableValidators="true" refreshId="panelMessage">
<xp:this.action><![CDATA[#{javascript:
applicationScope.testdatalist = null;
viewScope.message = "ApplicationScope data is cleared.";
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:br></xp:br>
<xp:panel id="panelMessage">
<xp:text escape="true" id="computedField1" value="#{viewScope.message}"></xp:text>
</xp:panel>
</xp:view>
なお、解析対象のヒープメモリには Java のクラスの情報しか載ってきません。MAT は JVM の解析用のツールなので、XPages やサーバーサイド JavaScript を直接解析することはできません。MAT を使用した XPages の解析では、XPages が JavaServer Faces のフレームワークで動いていることを理解する必要があります。
Domino Designer でメニューから「ウィンドウ」→「Eclipse ビューの表示」でパッケージエクスプローラーを表示することで、XPages から生成された Java クラスを見ることができます。今回作成した XPage は「MyXPagesApp」で、それから生成された Java クラスは xsp.MyXPageApp.java となっています。このあとで説明する MAT でメモリ解析の際には、この Java クラスを見ながら行うことになります。
ヒープダンプの取得
Domino サーバーの JVM のヒープダンプは、Domino コンソールから以下の XSP マネージャーコマンドで生成することができます。生成されたヒープダンプは、Domino のプログラムディレクトリに heapudump_<日付>.<時刻>.<ミリ秒>.<連番>.phd のファイル名で生成されます
このコマンドの小先は「XPages Portable Command Guide」の第3章「Chapter 3. Working with the Console」の「How to Execute the XSP Command Manager Commands」の節に記載されています。
ロードの方法
生成されたヒープダンプは MAT と IBM Diagnostic Tool Framework for Java を導入した で解析できます。Eclipse IDE を起動し、、メニュより「File」→「Open File」から生成したヒープダンプファイルを選択します。「Getting Start Wizard」で「Leak Suspects Report」を選択して「Finishi」をクリックします。
ヒープダンプが読み込まれるとともに、解析用の INDEX ファイルが同じフォルダに作成されます。また解析結果をポータブルに持ち運べるように ZIP ファイルも作成されます。
ヒープダンプが読み込まれるとメモリリークの疑われるコンポーネントがグラフで表示され、詳細情報へのリンクが表示されます。
ただしここに表示されるのはメモリの使用量の多い物を示しているだけで、本当にメモリリークかどうかは自身で判断する必要があります。
また、実際にメモリリークが起こっているときでもその量が大きくなければここでは表示されないことがあります。そのときには、このあとで紹介する Dominator Tree などで埋もれているメモリリークを探す必要があります。
この例では意図的にメモリリークを生成しているので「Suspect1」がメモリリークに該当します。「Suspect2」と「Suspect3」はこの場合は XPages フレームワークの正常な動作です。
「Suspect1」の「Detail」をクリックすることでこの詳細が表示されます。
ここでは 2,000,000 を超える極端に大きなヒープメモリを取っている Java のクラスがあり、XPages のクラスローダーから呼ばれていることが判ります。そして、それを呼び出しているのが xsp.MyXPagesApp クラスです。
先ほども書いたように、占有しているメモリの量がそれほど大きくないときには Leak Suspects には現れないことがあります。そのときには Dominator Tree でメモリの使用量を見てメモリリークをしている箇所を探すことになります。
以下の Dominator Tree の例では、NSFComponentModule が大きなヒープメモリを占有しており、その大半が Vector に使用されています。このインスタンスから「Path to GC Roots」を選択して親を探します。すると先ほどと同じように xsp.MyXPagesApp クラスが見つかります。
この例でははっきりと判るメモリのリークを生み出して調べてみました。実際の環境では微妙なサイズのメモリリークが複数存在することになり、Dominator Tree などでメモリの量を見ながらひとつひとつ原因を究明することになります。